import wx
import pythoncom, pyHook
import ctypes
import sys
from WinOSCommands import getWindowList, showWindow

#makes the pretty round shape stuff...
def GetRoundBitmap(w, h):
    maskColor = wx.Color(0,0,0)
    shownColor = wx.Color(5,5,5)
    b = wx.EmptyBitmap(w,h)
    dc = wx.MemoryDC(b)
    dc.SetBrush(wx.Brush(maskColor))
    dc.SetBrush(wx.Brush(shownColor))
    dc.SetPen(wx.Pen(shownColor))
    dc.DrawRoundedRectangle(0,0,w,h,10)
    dc.SelectObject(wx.NullBitmap)
    b.SetMaskColour(maskColor)
    return b

def GetRoundShape(w, h):
    return wx.RegionFromBitmap( GetRoundBitmap(w,h) )

#windows we don't want to switch to, including ourself and the desktop (XP name, not quite sure what the name in Win 7 is)
IGNORED_APPLICATIONS = ['Type-O-Switcher','Program Manager'] 

class Switcher(wx.Frame):
    
    trackInput = False
    
    def __init__(self, parent):

        #create the beautiful interface... sorry, I always make a mess of this, can't really get my around frames, panels, and sizers..
#        wx.Frame.__init__(self, parent, title="Type-O-Switcher", style=wx.SYSTEM_MENU|wx.CAPTION|wx.CLOSE_BOX|wx.STAY_ON_TOP)
        #pretty bubble style
        wx.Frame.__init__(self, parent, title="Type-O-Switcher", style=wx.FRAME_SHAPED |
                          wx.NO_BORDER |
                          wx.FRAME_NO_TASKBAR |
                          wx.STAY_ON_TOP|
                          wx.CLIP_CHILDREN)
        self.parent = parent
        self.initialize()

    def initialize(self):        
        self.SetSize( (600, 300) )
        self.SetPosition( (400,300) )
        self.SetTransparent(240)
        
        #platform depended frame shaping
        if wx.Platform == "__WXGTK__":
            self.Bind(wx.EVT_WINDOW_CREATE, self.SetRoundShape())
        else:
            self.SetRoundShape()
                  
        font = wx.Font(20, wx.SWISS, wx.NORMAL, wx.NORMAL, False, 'Verdana') 
        bold = wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False, 'Verdana')  
        small = wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD, False, 'Verdana')    
        
        #different pinks
        brightpink = wx.Colour(255, 0, 127)
        deeppink = wx.Colour(255, 20, 147)  
        shockingpink = wx.Colour(252, 15, 192)
              
        self.SetBackgroundColour("gray")
        self.panel = wx.Panel(self,wx.ID_ANY)
        self.vbox = wx.BoxSizer(wx.VERTICAL)
        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
#        self.typeIn = wx.StaticText(self.panel, typeIn=" Type-O-Switcher ")
        self.typeIn = wx.TextCtrl(self.panel, wx.ID_ANY, '' , style=wx.TE_RICH|wx.WANTS_CHARS|wx.BORDER_NONE)
        self.typeIn.SetBackgroundColour('light blue')
#        self.typeIn.SetForegroundColour('pink')
        self.typeIn.SetFont(font)
        self.blankTop = wx.StaticText(self.panel, wx.ID_ANY, label="Type-O-Switcher", style=wx.ALIGN_CENTER)
        self.blankTop.SetFont(bold)
#        self.blankTop.SetForegroundColour('pink')
        self.blankTop.SetForegroundColour(deeppink)
        self.blankBottom = wx.StaticText(self.panel, wx.ID_ANY, label="\n")
        self.windowsLabel = wx.StaticText(self.panel, wx.ID_ANY, style=wx.ST_NO_AUTORESIZE)
        self.windowsLabel.SetFont(small)
        self.windowsLabel.SetForegroundColour('yellow')
        
        self.vbox.Add(self.blankTop, 1,wx.EXPAND)
        self.vbox.Add(self.typeIn, 1,wx.EXPAND)
        self.vbox.Add(self.windowsLabel, 3,wx.EXPAND)
        self.vbox.Add(self.blankBottom, 1,wx.EXPAND)
        self.panel.SetSizer(self.vbox)
        self.hbox.Add(self.panel, 1, wx.EXPAND)
        self.SetSizer(self.hbox)
        self.Layout()

        
        #GUI TESTING
        self.launch()
        
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) #I seem to have trouble 'properly' closing my wx windows, so ugly hack

        self.setHooks() #set the keyboard hooks
        
        #make sure everything is clear
        self.trackInput = False
        self.keys = ''
        
    #UIgraphics stuff
    def SetRoundShape(self, event=None):
        w, h = self.GetSizeTuple()
        self.SetShape(GetRoundShape( w, h) )   
        
    #should update shape of frame if list of open windows is long
    def UpdateRoundShape(self):
        size = self.GetSize()
        dc = wx.MemoryDC()
        textlabel = self.windowsLabel.GetLabel()
        textfont = self.windowsLabel.GetFont()
        textextent = dc.GetFullTextExtent(textlabel, textfont) 
        #word extending
        spaceless = textlabel.split('\n')
        maxwidth=0
        for i in spaceless:
            wordextent = dc.GetFullTextExtent(i, textfont)
            if wordextent[0]>maxwidth:
                maxwidth = wordextent[0]
        if maxwidth > size[1]:
            boxwidth = 300+maxwidth-300
        else:
            boxwidth = 300
        #end wordextend
        ns = len(spaceless)    

        boxheight = textextent[1]*ns+10
        self.windowsLabel.SetSize((boxwidth, boxheight))
        self.SetSize( (boxwidth, boxheight) )
        self.SetShape(GetRoundShape( boxwidth, boxheight) )
        
    def OnCloseWindow(self, evt):
        sys.exit() #brutally kill the program when you click the close box
        
    def setHooks(self):
        #Create a hook manager
        self.hm = pyHook.HookManager()
        # watch for all keyboard events
#        self.hm.KeyDown = self.OnKeyDown
        self.hm.KeyUp = self.OnKeyUp
        # set the hook
        self.hm.HookKeyboard()
        # wait forever
        pythoncom.PumpMessages()
        
#    def OnKeyDown(self, event):
#        if event.Key == 'F12' and not self.trackInput: #for showing...
#            print 'DOWN F12'
#            self.launch() 
        
    def OnKeyUp(self, event):
#        print self.FindFocus(), event.Key 
        if event.Key == 'F12': #for showing...
            self.launch()
#            self.kill() 
        elif event.Key == 'Escape': #and hiding...
            self.kill() 
        elif self.trackInput:
            self.keys += event.Key.lower() #add typed keys, convert all to lower just 'cause it's handy
#            self.typeIn.SetLabel(self.keys)
            self.checkForWindow(self.keys) #check if there is a unique window with those keys in the title
        return True
            
    def launch(self):
        self.trackInput = True #trackInput is used in the OnKeyUp hook
        self.keys = '' #reset typed text
        self.Show()
        self.SetFocus()
        self.typeIn.SetFocus()
        self.Raise()
        
    def kill(self):
        self.trackInput = False
        self.Hide()
        
    def checkForWindow(self, s):
        #checks if any of the windows is in the ignore app list
        currentWindows = [w for w in getWindowList() if w[1] not in IGNORED_APPLICATIONS ]
        #print window titles on label
        txt = ''
        for i, w in enumerate(currentWindows):
            txt+='\t'+str(w[1])+'\n'
        self.windowsLabel.SetLabel(txt)    
        
        numFound = 0
        for window in currentWindows:
#            print window[0],window[1]
            if s in window[1].lower():
                numFound += 1
                hwnd = window[0]
                wintit = window[1]
        if numFound == 1: #switch only if we found a unique match... not a very charming way of doing it, you could stop the search loop (above) when more than 1 has been found, but it's midnight and I'm lazy
            print hwnd, wintit
#            self.kill()
#            showWindow(hwnd) #switch to the window! rejoice!
            
            
class MyApp(wx.App):
    def OnInit(self):

        sframe = Switcher(None)
        self.SetTopWindow(sframe)
        return True


app = MyApp(0)
app.MainLoop()
